查看原文
其他

汇编层面分析函数调用

Jabez 看雪学院 2019-05-26


前言

汇编语言是学习逆向的基础,本文通过从汇编的层面分析函数调用来了解压栈、跳转、执行、返回的具体实现流程以及对堆栈的应用。


知识有限,如果有错误或则不清楚的地方还请您指出。


您的鼓励是我写文章的动力。



1. 函数调用的说明


在介绍函数调用的具体流程前,我们先来了解一下几个知识点。


  • 1.1 程序的执行流程


程序是顺序执行的,cpu是怎么进行实现的呢?


程序的执行离不开一个关键的寄存器。


我们首先来了解一下关于程序计数器的概念。


百度百科:



由此可见,程序计数器的功能就是存放下一条要执行指令的地址。


在X86汇编中,执行程序计数功能的寄存器叫做EIP,指令指针寄存器。


我们可以写个简单的程序,查看反汇编了解一下。



EIP寄存器里面存放的就是即将要执行指令的地址。


  • 1.2 程序的栈结构


在经典的操作系统里,栈总是向下增长的。栈顶由esp寄存器定位。压栈操作使栈顶的地址减小,弹出操作使栈顶地址增大。


函数的调用离不开栈,栈中保存了函数调用当中的所有信息。


  • 函数的返回地址和参数;

  • 函数的非静态的局部变量;

  • 保存上下文:保存一些不需要改变的寄存器。


为了能够正确的处理函数调用的堆栈平衡,我们需要更正两个寄存器ebp,esp的位置:


1. 把ebp提升到esp的位置。



2. esp的值是动态变化的,随着申请更多的临时变量,e's'p会不断减小。


3. 调用函数后栈中的结构图。



  • 1.3 调用约定及堆栈平衡


在函数调用过程中,参数需要提前压栈,而在函数调用结束后,之前压栈的参数也需要退栈。


这样就有一个问题,退栈的工作是交给调用者完成还是交给被调用函数完成?


这就需要有个约定。


常见调用约定的堆栈平衡方式:

 调用约定 堆栈平衡方式
 __stdcall 函数自己平衡
 __cdecl 调用者负责平衡
 __thiscall 调用者负责平衡
 __fastcall 调用者负责平衡
 __naked 有编写者负责












2. 函数调用的流程


了解了基本的概念之后,回到主题:函数调用


  • 压栈:函数参数压栈 返回地址压栈

  • 跳转:跳转到函数所在代码处执行

  • 执行:执行函数代码

  • 返回:平衡堆栈 找出返回地址并跳回


  • 2.1 call指令

0x210000 call swap;
0x210005 mov ecx,eax;


call指令可以分解成两个指令:

push 0x210005;
jmp swap;


首先push当前指令下一条指令的地址,目的是调用完函数后可以跳回来;


然后修改eip,跳到函数的地址。


  • 2.2 ret指令 


ret指令表示取出当前栈顶值作为返回地址,将eip修改为该地址。


执行完这一步一个基本的函数调用就完成了。



3. 函数调用汇编实验


测试程序


在main函数中调用一个交换两个数的函数。

#include <stdio.h>


void _stdcall swap(int& a,int& b);


//交换两个数
void _stdcall swap(int& a, int& b)
{
   int c = a;
   a = b;
   b = c;
}


void main()
{

   int a = 1;
   int b = 2;
   printf("交换前:a =%d,b=%d\n",a,b);
   swap(a,b);
   printf("交换后:a= %d,b=%d\n",a,b);

   getchar();

}


程序的运行结果:



  • 3.1 压栈


    • 3.1.1 函数参数压栈


真正调用函数前先将参数进行压栈。



我们通过观察寄存器和内存来查看变化过程:



发现参数已经被压入栈中。


    • 3.1.2 返回地址压入栈中


F11进入swap函数后,可以发现内存当中凭空出现一段数,它是什么?



其实它就是call指令的下一条指令的地址:



  • 3.2 跳转


跳转到swap函数内部,下面是详细注解



  • 3.3 返回


执行ret前。



执行ret后,帖前先滑动左侧填充拼图:



由于使用的是__stdcall的调用约定,在被调用函数内部进行堆栈平衡。


4. 结语


这样,一个函数调用的实现就分析完成了。有好多细节的问题没有进行阐述。这样一篇文章用来总结汇编的知识点,希望遇到同道中人。


成为逆向大牛的过程是艰辛的,你已经迈出了第一步,加油。



- End -


看雪ID:Jabez                      

https://bbs.pediy.com/user-825190.htm



本文由看雪论坛 Jabez 原创

转载请注明来自看雪社区



书籍推荐:


  • 《加密与解密》

是一本逆向必读书籍。本书以软件逆向为切入点,讲述了软件安全领域相关的基础知识和技能,可以说是安全人士必读书籍之一了。


看雪推荐“解密”前的过渡书籍:

  • 基普·欧文的《汇编语言:基于x86处理器》

  • 王爽的《汇编语言》

  • Charles Petzold著的《Windows程序设计》(以VC来讲解)


长按识别二维码,即可购买以上书籍



热门技术文章推荐:





戳原文,看看大家都是怎么说的?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存